by Alyce Watson
What is a Subroutine?
A subroutine is also called a subprogram. It is a self-contained section of code that can be called from other parts of the program. It can be called many times. If code that is to be reused many times is placed in a subroutine, the program has fewer lines of code. It is easier to read and to modify. Liberty BASIC has two kinds of subroutines, the GOSUB and the SUB.
GOSUBS
A subroutine that is called by GOSUB [branchLabel] is part of the main program and shares its memory space. It begins with a branch label and ends with the keyword RETURN. When the RETURN keyword is encountered, the program execution returns to the next line after the GOSUB command that called the routine. Here is an example:
Print "Starting program!" gosub [printHello] print "Ending program!" END [printHello] print "Hello, you are in a gosub!" RETURN
GOSUB Rules
'WRONG! [begin] print "Hello World" [myGosub] print "I've visited a gosub!" RETURN ' 'Right: print "Hello World" WAIT [myGosub] print "I've visited a gosub!" RETURN
Called Subroutines
Called subroutines (subs) differ in many respects from GOSUB subroutines. The general form of a called subroutine is as follows:
Sub SubName arg1, arg2,... argN
'some code here
End Sub
The sub definition is signalled by the keyword Sub. It is followed by the sub's name, then a list of arguments, separated by commas. The argument list must not be placed inside of parentheses. The next lines contain whatever code routine is performed by the sub. The sub definition must end with End Sub.
The Argument List
The arguments may be string, numeric, or a mixture of both. They may be literal values, variables, or expressions. The arguments must be separated by commas. These arguments are actually variables that are local to the sub. They can be used in code contained in the sub. When the sub ends, the variables no longer have any value. A sub can exist without arguments, in which case the sub name is not followed by anything.
The names given to the argument variables in the sub definition represent variables that are local to the sub. When the sub is called, whatever literal value, expression or variable is contained within the commas will be evaluated and given the corresponding name in the argument list. See the following examples for a demonstration of the argument list. Notice in the last example, the variable names used to call the sub are the same names used in the sub, but in a different order. (They are name1$ and name2$.) This doesn't matter, because the argument variables are local to the sub and are not the same variables as the ones with the exact same names used in the main program.
call LongestName "Sam","Patricia"
first$="Carl"
last$="Gundel"
call LongestName last$,first$
name1$="Liberty"
name2$="BASIC"
call LongestName name2$,name1$
end
Sub LongestName name1$,name2$
if len(name1$)>len(name2$) then
print name1$ + " is the longest."
else
print name2$ + " is the longest."
end if
End Sub
Results in:
Patricia is the longest.
Gundel is the longest.
Liberty is the longest.
Scope
Subs have their own memory space that is separate from the memory of the main portion of the program. Variables and branch labels that exist inside of the sub do not exist in the main program. The main program cannot "see" them. Likewise, subs cannot "see" variables and branch labels that exist in the main program, or in other subs, or functions. The part of the program that can "see" a variable is called its "scope."
Some entities have global scope. That is, they can be seen both inside of subs and in the main program. These things are global in scope: arrays, handles (window and control handles, file handles, DLL handles, communications ports), and structs. In Liberty BASIC 3, if a value from the main program must be visible inside a sub, the value can be held in an array, or passed into the sub as one of the arguments. In Liberty BASIC 4, variables can be declared as GLOBAL, which means that they can be seen from all parts of a program.
Special global status is given to certain default variables used for sizing, positioning, and coloring windows and controls. These include variables WindowWidth, WindowHeight, UpperLeftX, UpperLeftY, ForegroundColor$, BackgroundColor$, ListboxColor$, TextboxColor$, ComboboxColor$, TexteditorColor$. The value of these variables can be seen in any sub. If these variables are used in any way, they become local to the sub. For instance, a window opened inside a sub will open with a width equal to the current WindowWidth. If WindowWidth is used in any way, it becomes local to the sub. As an example, if the sub includes this line:
ww = WindowWidth
WindowWidth no longer has the value it has outside the sub. To test this try the following small demo.
print WindowWidth
call ShowWindowWidth
end
Sub ShowWindowWidth
print WindowWidth
End Sub
The results of the program:
320
0
Calling Subs
Subs are called by using the keyword CALL followed by the name of the sub, then a comma separated list of arguments. When the sub exits, program execution returns to the line after the CALL command.
Sub Rules
'WRONG! Call MySub 1,2 Sub MySub num1,num2 print num1+num2 End Sub ''''''''''''''''''''''''''' 'RIGHT! Call MySub 1,2 wait 'this line halts the program so it doesn't enter the function Sub MySub num1,num2 print num1+num2 End Sub '
Subs as Event Handlers
Liberty BASIC 4 allows us to use Subs as event handlers. In previous versions of Liberty BASIC, branch labels were used as event handlers. When a Sub is used as an event handler, the argument list contains things like the handle of the control or window that fired the event, the MouseX and MouseY values, and the value of Inkey$. Future newsletters will contain more detailed information about using Subs as event handlers. Here is a small example of a button event handler Sub.
nomainwin
button #main.exit, "Exit", exitClicked, UL, 10, 10
open "Button Example" for window as #main
[loop]
wait
sub exitClicked buttonhandle$
notice "The button handle is ";buttonhandle$;" Goodbye."
close #main
end
end sub
Subroutines in Action
Here is a demo that changes the case of all words in a string so that the first letter is uppercase and the remaining letters are lowercase. Run the little demo to see how it works. Notice that the code inside the sub uses several native LB string functions.
call NameCase "hello world"
call NameCase "CARL GUNDEL"
call NameCase "tiTaNiC"
end
Sub NameCase name$
nm$=word$(name$,1)
while nm$<>""
i = i + 1
nm$=word$(name$,i)
first$=upper$(mid$(nm$,1,1))
rest$=lower$(mid$(nm$,2))
new$=new$+" "+first$+rest$
wend
print "Name is now ";trim$(new$)
End Sub
Here is a simple numeric sub that prints the average of three values.
call Average 15,88,20
call Average 10,20,30
end
Sub Average num1,num2,num3
print "Average is ";(num1+num2+num3)/3
End Sub
Here is the same routine, but this one uses a GOSUB subroutine. GOSUB subroutines do not accept input arguments, but they can "see" values in the main program, because they are actually part of the main program and share its memory space. Note the differences between the two methods:
num1=15
num2=88
num3=20
gosub [Average]
num1=10
num2=20
num3=30
gosub [Average]
end
[Average]
print "Average is ";(num1+num2+num3)/3
RETURN
GOSUB or Sub?
Use a GOSUB routine when:
Use a called SUB when: